package ai.esc.speedy.common.util.id;

import ai.esc.speedy.common.util.IPUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

@Slf4j
@AllArgsConstructor
@Service
public class WorkerIdService {

    private final WorkerIdRepository workerIdRepository;
    // private final Registration registration;
    // private final NacosRegistration registration;

    Long getWorkerId() {

        String serviceKey = getServiceKey();
        WorkerId workerId = workerIdRepository.findByServiceKey(serviceKey);

        if (workerId != null) {
            return workerId.getId() % (SnowFlake.MAX_MACHINE_NUM + 1);
        }

        workerId = new WorkerId();
        // 如果你的 Spring Boot 版本 >= 2.1.0 并且使用的 Discovery 提供了该方法的实现则可以直接使用
        // workerId.setServiceKey(registration.getInstanceId());
        workerId.setServiceKey(serviceKey);
        workerIdRepository.save(workerId);
        return workerId.getId() % (SnowFlake.MAX_MACHINE_NUM + 1);
    }

    /**
     * 由于 Spring Cloud Discovery 的 ServiceInstance 接口没有一个获取 instance id 的方法，所以只能想办法自己标记
     * Spring Cloud Discovery 在 2.1.0 之后的版本在接口中提供了 getInstanceId 这一方法，但是可以为空，所以需要各个实现，我看了 K8S 和 consul 都提供了该方法的实现
     * <p>
     * 获取 IP 和 MAC 作为唯一 Key 存入数据库，获取到自增 ID，然后对 Snowflake 的最大 Worker ID 取余，这样便得到了一个可用的 Worker ID。
     *
     * @return ip:mac_address 形式的字符串
     */
    private String getServiceKey() {

        String hostAddress = null;
        try {
            hostAddress = IPUtil.getIpAddress();
            log.info("本机IP：" + hostAddress);
        } catch (SocketException e) {
            log.error("获取IP失败！", e);
        }

        byte[] mac = new byte[0];
        try {
            mac = Objects.requireNonNull(IPUtil.getMacAddress()).getBytes();
            log.info("本机MAC：" + new String(mac, StandardCharsets.UTF_8));
        } catch (SocketException e) {
            log.error("获取MAC失败！", e);
        }

        if (mac.length <= 0 || StringUtils.isBlank(hostAddress)) {
            return null;
        }

        // mac地址拼装成String
        StringBuilder macAddress = new StringBuilder();
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                macAddress.append("-");
            }
            // mac[i] & 0xFF 是为了把byte转化为正整数
            String s = Integer.toHexString(mac[i] & 0xFF);
            macAddress.append(s.length() == 1 ? 0 + s : s);
        }
        // 把字符串所有小写字母改为大写成为正规的mac地址并返回
        return hostAddress + ":" + macAddress.toString().toUpperCase();
    }

}


